// Package httpclient implements HTTP client initialization and message processing
package httpclient

import (
	"crypto/tls"
	"crypto/x509"
	"gitee.com/ascend/mapper-go-sdk/internal/config"
	"gitee.com/ascend/mapper-go-sdk/internal/httpadapter"
	"gitee.com/ascend/mapper-go-sdk/pkg/di"
	"github.com/gorilla/mux"
	"io/ioutil"
	"k8s.io/klog/v2"
	"net/http"
	"os"
	"time"
)

// HttpClient is structure used to init HttpClient
type HttpClient struct {
	IP             string
	Port           string
	WriteTimeout   time.Duration
	ReadTimeout    time.Duration
	server         *http.Server
	restController *httpadapter.RestController
}

// NewHttpClient initializes a new Http client instance
func NewHttpClient(dic *di.Container) *HttpClient {
	return &HttpClient{
		IP:             "0.0.0.0",
		Port:           "1215",
		WriteTimeout:   5 * time.Second,
		ReadTimeout:    5 * time.Second,
		restController: httpadapter.NewRestController(mux.NewRouter(), dic),
	}
}

// Init is a method to construct HTTP server
func (hc *HttpClient) Init(c config.Config) error {
	hc.restController.InitRestRoutes()
	caCrtPath := c.Http.CaCert
	pool := x509.NewCertPool()
	crt, err := ioutil.ReadFile(caCrtPath)
	if err != nil {
		klog.Errorf("Failed to read cert %s:%v", caCrtPath, err)
		os.Exit(1)
	}
	pool.AppendCertsFromPEM(crt)
	hc.server = &http.Server{
		Addr:         hc.IP + ":" + hc.Port,
		WriteTimeout: hc.WriteTimeout,
		ReadTimeout:  hc.ReadTimeout,
		Handler:      hc.restController.Router,
		TLSConfig: &tls.Config{
			ClientCAs: pool,
			// check client certificate file
			ClientAuth: tls.RequireAndVerifyClientCert,
		},
	}
	klog.V(1).Info("HttpServer Start......")
	go func() {
		_, err := hc.Receive(c)
		if err != nil {
			klog.Errorf("Http Receive error:%v", err)
		}
	}()
	return err
}

// UnInit is a method to close http server
func (hc *HttpClient) UnInit() {
	err := hc.server.Close()
	if err != nil {
		klog.Error("Http server close err:", err.Error())
		return
	}
}

// Send no messages need to be sent
func (hc *HttpClient) Send(message interface{}) error {
	return nil
}

// Receive http server start listen
func (hc *HttpClient) Receive(c config.Config) (interface{}, error) {
	serverCrtPath := c.Http.Cert
	serverKeyPath := c.Http.PrivateKey
	err := hc.server.ListenAndServeTLS(serverCrtPath,
		serverKeyPath)
	if err != nil {
		return "", err
	}
	klog.Error("HTTP Server exited")
	return "", nil
}
